Java Database Programming with JDBC Java Database Programming with JDBC
by Pratik Patel
Coriolis, The Coriolis Group
ISBN: 1576100561   Pub Date: 10/01/96
  

Previous Table of Contents Next


Listing 10.9 Machine-generated C file for native methods.

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <StubPreamble.h>

/* Stubs for class jdbc/test/MyBridge */
/* SYMBOL: "jdbc/test/MyBridge/getINTSize()I", Java_jdbc_test_MyBridge_getINTSize_stub  */
__declspec(dllexport)  stack_item
*Java_jdbc_test_MyBridge_getINTSize_stub(stack_item  *_P_,struct
execenv
*_EE_) {
      extern long jdbc_test_MyBridge_getINTSize(void *);
      _P_[0].i = jdbc_test_MyBridge_getINTSize(_P_[0].p);
    return _P_ + 1;
    }
    /* SYMBOL: "jdbc/test/MyBridge/getINTValue([B)I",
     Java_jdbc_test_MyBridge_getINTValue_stub */
      __declspec(dllexport) stack_item
      *Java_jdbc_test_MyBridge_getINTValue_stub(stack_item *_P_,struct  execenv *_EE_) {
     extern long jdbc_test_MyBridge_getINTValue(void *,void *);
       _P_[0].i = jdbc_test_MyBridge_getINTValue(_P_[0].p,((_P_[1].p)));
    return _P_ + 1;
}
/*  SYMBOL: "jdbc/test/MyBridge/callSomeFunction(Ljava/lang/String;[B)V",
Java_jdbc_test_MyBridge_callSomeFunction_stub  */
__declspec(dllexport)   stack_item
*Java_jdbc_test_MyBridge_callSomeFunction_stub(stack_item    *_P_,struct
execenv *_EE_) {
          extern void jdbc_test_MyBridge_callSomeFunction(void *,void *,void
    *);
            (void) jdbc_test_MyBridge_callSomeFunction(_P_[0].p,((_P_[1].p)),
          ((_P_[2].p)));return _P_;
}

The bridge code is shown in Listing 10.10. The function prototypes were taken from the generated header file.

Listing 10.10 Bridge code.

//------------------------------------------------------------------------
// MyBridge.c
//
// Sample code to demonstrate the use of native methods
//------------------------------------------------------------------------
#include <stdio.h>
#include <ctype.h>
#include <string.h>

// Java internal header files
#include "StubPreamble.h"
#include "javaString.h"

// Our header file generated by JAVAH
#include "jdbc_test_MyBridge.h"

//------------------------------------------------------------------------
// getINTSize
// Return the size of an int
//------------------------------------------------------------------------
long   jdbc_test_MyBridge_getINTSize(
      struct Hjdbc_test_MyBridge *caller)
{
    return sizeof(int);
}

//------------------------------------------------------------------------
// getINTValue
// Given a buffer, return the value as an int
//------------------------------------------------------------------------
long jdbc_test_MyBridge_getINTValue(
    struct Hjdbc_test_MyBridge *caller,
    HArrayOfByte *buf)
{
    // Cast our array of bytes to an integer pointer
     int* pInt = (int*) unhand (buf)->body;

    // Return the value
     return (long) *pInt;
}

//------------------------------------------------------------------------
// callSomeFunction
// Call some function that takes a String and an int pointer as arguments
//------------------------------------------------------------------------
void jdbc_test_MyBridge_callSomeFunction(
    struct Hjdbc_test_MyBridge *caller,
    struct Hjava_lang_String *stringValue,
    HArrayOfByte *buf)
{

    // Cast the string into a char pointer
    char* pString = (char*) makeCString (stringValue);

    // Cast our array of bytes to an integer pointer
    int* pInt = (int*) unhand (buf)->body;

     // This fictitious function will print the string, then return the
    // length of the string in the int pointer.
      printf("String value=%s\n", pString);
     *pInt = strlen(pString);
}

Now, create a library (DLL or Shared Object) by compiling this module and linking it with the jdbc_test_MyDriver compiled object and the one required Java library, javai.lib. Here’s the command line I used to build it for Win95/NT:

cl -DWIN32 mybridge.c jdbc_test_mybridge.c -FeMyBridge.dll -MD -LD javai.lib

Now we can use our native bridge, as shown in Listing 10.11.

Listing 10.11 Implementing the bridge.

import jdbc.test.*;
import java.sql.*;

class Test {

     public static void main (String args[]) {

        MyBridge myBridge = null;
         boolean loaded = false;

        try {

            // Create a new bridge object. If it is unable to load our
            // native library, an SQLException will be thrown.
            myBridge = new MyBridge();
            loaded = true;
        }
        catch (SQLException ex) {
            System.out.println("SQLException: " + ex.getMessage());
        }

        // If the bridge was loaded, use the native methods
         if (loaded) {

            // Allocate storage for an int
             byte intValue[] = new byte[myBridge.getINTSize()];

            // Call the bridge to perform some function with a string,
            // returning a value in the int buffer.
             myBridge.callSomeFunction("Hello, World.", intValue);

            // Get the value out of the buffer.
             int n = myBridge.getINTValue(intValue);

            System.out.println("INT value=" + n);
        }
    }
}

Listing 10.11 produces the following output:

String value=Hello,  World.
INT value=13

As you can see, using native methods is very straightforward. Developing a JDBC driver using a native bridge is a natural progression for existing database systems that provide a C API. The real power and ultimate solution, though, is to develop non-native JDBC drivers—those consisting of 100 percent Java code.

Implementing Interfaces

The JDBC API specification provides a series of interfaces that must be implemented by the JDBC driver developer. An interface declaration creates a new reference type consisting of constants and abstract methods. An interface cannot contain any implementations (that is, executable code). What does all of this mean? The JDBC API specification dictates the methods and method interfaces for the API, and a driver must fully implement these interfaces. A JDBC application makes method calls to the JDBC interface, not a specific driver. Because all JDBC drivers must implement the same interface, they are interchangeable.

There are a few rules that you must follow when implementing interfaces. First, you must implement the interface exactly as specified. This includes the name, return value, parameters, and throws clause. Secondly, you must be sure to implement all interfaces as public methods. Remember, this is the interface that other classes will see; if it isn’t public, it can’t be seen. Finally, all methods in the interface must be implemented. If you forget, the Java compiler will kindly remind you.

Take a look at Listing 10.12 for an example of how interfaces are used. The code defines an interface, implements the interface, and then uses the interface.


Previous Table of Contents Next